/* 
 * 	This file is part of VPN Monitor Project 7..

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package monitor.utility;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Collections;
import java.util.LinkedList;

/**
 * Utility class contains static methods used for: <br>
 * Reading traffic under Ubuntu maybe also work under other linux systems. <br>
 * Checking if an interface is present among all active interfaces <br>
 * Getting all available interfaces that are up. <br>
 * Reporting traffic from byte to more readable form. *
 */
public class Utility {
	/**
	 * Get the traffic from the file '/proc/net/dev' for a specific
	 * interface. The method return the traffic in number of bytes in
	 * an array of size three. Traffic type is in the following order
	 * download, upload & traffic.
	 * 
	 * @param network
	 * 			The interface for which traffic information is desired.		
	 * @return
	 * 			Array of the size three with traffic in bytes, in the order that
	 * 			follows. Download, Upload, Total. If the interface isn't found
	 * 			will null be returned.
	 * 
	 * @throws FileNotFoundException If the file '/proc/net/dev' isn't found.
	 */
	public static long[] readTraffic(String network) throws FileNotFoundException, InterfaceNotFoundException{
		final String fileName = "/proc/net/dev"; 
		File file = new File(fileName);
		long[] values = new long[3];
		String line = null, tok[] = null;
		if (!file.exists())
			throw new FileNotFoundException(fileName + " don't exist");
		else if(!file.canRead())
			throw new FileNotFoundException("Can't read " + fileName);
		try {
			int x = 0;
			BufferedReader read = new BufferedReader(new FileReader(file));
			while ((line = read.readLine()) != null) {
				if (x++ < 2 || !line.contains(network))
					continue;
				break;
			}
		} catch (IOException e) {}
		if (line == null)
			throw new InterfaceNotFoundException("Unable to find " + network + " in "	+ file.toString() + ".");
		line = line.replace(':', ' ');
		tok = line.split("\\s+");
		values[0] = Long.parseLong(tok[2]);
		values[1] = Long.parseLong(tok[10]);
		values[2] = values[0]+values[1];
		return values;
	}

	/**
	 * Check if a specific interface exists.
	 * 
	 * @param interfaceName Interface to look for.
	 * @return True - if it's found, otherwise false.
	 */
	public static boolean checkInterface(String interfaceName) {
		try {
			for (NetworkInterface netint : Collections.list(NetworkInterface.getNetworkInterfaces())) 
				if (interfaceName.equals(netint.getDisplayName()) || interfaceName.equals(netint.getName())) 
					return true;
		} catch (SocketException eX) {
			eX.printStackTrace();
		}
		return false;
	}

	/**
	 * Get all available interfaces that is up and that aren't loopback.
	 * @return Array of the avaible interfaces.
	 */
	public static String[] getAvailableInterfaces() {
		try {
			LinkedList<String> nets = new LinkedList<String>();
			for(NetworkInterface n : Collections.list(NetworkInterface.getNetworkInterfaces()))
				if(!n.isLoopback() || !n.isUp())
					nets.add(n.getName());
			return nets.toArray(new String[nets.size()]);
		} catch (SocketException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Transform a amount of byte to GB, MB, kB or byte depending on the amount of bytes
	 * specified in 'traffic'. It also possible to specify what detail the reporting should have
	 * with detail level of four will give full detail. For total byte of over 1 billion will
	 * GB, MB, kB & byte be reported. It should be noted that it's the SI system that is used
	 * one kB equals 1000 bytes and not 1024 bytes.
	 * 
	 * @param traffic Total number of bytes
	 * @param detail Desired report level.
	 * @return Traffic as a string, if traffic is zero will it report "0 byte".
	 */
	public static String reportTraffic(long traffic, int detail) {
		StringBuilder print = new StringBuilder();
		int count = 0;
		if ((detail > count) && (long) (traffic / 1E+9) > 0) {
			count++;
			print.append((long) (traffic / 1E+9)).append("GB ");
			traffic = traffic - (long) (traffic / 1E+9) * (long) 1E+9;
		}
		if ((detail > count) && (long) (traffic / 1E+6) > 0) {
			count++;
			print.append((long) (traffic / 1E+6)).append("MB ");
			traffic = traffic - (long) (traffic / 1E+6) * (long) 1E+6;
		}
		if ((detail > count) && (long) (traffic / 1E+3) > 0) {
			count++;
			print.append((long) (traffic / 1E+3)).append("kB ");
			traffic = traffic - (long) (traffic / 1E+3) * (long) 1E+3;
		}
		if ((detail > count) && traffic > 0) {
			count++;
			print.append(traffic).append("byte");
		}
		if (count == 0)
			print.append("0 byte");
		return print.toString();
	}
}
